package org.springblade.modules.netty;

import com.alibaba.fastjson.JSON;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.util.concurrent.GlobalEventExecutor;
import org.springblade.core.redis.cache.BladeRedis;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.modules.system.entity.User;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * netty服务端
 * 因为netty的Handler无法注入spring对象，所以用工具类
 */
public class NettyHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {
    private static BladeRedis bladeRedis;

    static {
        bladeRedis = SpirngBeanUtil.getBean(BladeRedis.class);
    }

    //所有客户端的channel集合 foreach可以遍历拿到单个channel
    private static ChannelGroup clients = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

    //客户端上线
    @Override
    public void handlerAdded(ChannelHandlerContext channel) throws Exception {
        clients.add(channel.channel());
    }

    //客户端下线
    @Override
    public void handlerRemoved(ChannelHandlerContext channel) throws Exception {
        try {
            Map<Object, Object> map = bladeRedis.hGetAll("dmj:netty");
            map.remove(channel.channel().id().asShortText());
            bladeRedis.del("dmj:netty");
            bladeRedis.hMset("dmj:netty", map);
        } catch (Exception e) {
            System.out.println("redis移除失败");
        }
        clients.remove(channel.channel());
    }

    //这个方法实际上是channelRead方法调用的 详情可以看一下源码 不需要释放
    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame textWebSocketFrame) throws Exception {
        String msg = textWebSocketFrame.text();
        Channel channel = channelHandlerContext.channel();
        if (msg.contains("{") && msg.contains("}")) {
            NettyVo vo = JSON.parseObject(msg, NettyVo.class);
            if ("0".equals(vo.getType())) {
                heartbeat(channel, vo);
            }
        }
    }

    //心跳
    protected void heartbeat(Channel channel, NettyVo vo) {
        String value = "";
        if (StringUtil.isNoneBlank(vo.getCuserid())) {
            value = vo.getCuserid();
        }
        if (StringUtil.isNoneBlank(vo.getWorkerid())) {
            value = vo.getWorkerid();
        }
        Map<Object, Object> map = bladeRedis.hGetAll("dmj:netty");
        map.put(channel.id().asShortText(), value);
        bladeRedis.hMset("dmj:netty", map);
        NettyVo result = NettyVo.builder()
                .type("0")
                .time(vo.getTime())
                .build();
        channel.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(result)));
    }

    //给工人群发订单信息
    public static void handleOrderWorkerList(List<User> userList, String msg) {
        //redis中存的
        Map<String, String> channelMap = bladeRedis.hGetAll("dmj:netty");
        Map<Long, Long> workerMap = userList.stream().collect(Collectors.toMap(User::getId, User::getId, (key1, key2) -> key2));
        ChannelGroup group = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);
        for (Channel channel : clients) {
            String workerid = channelMap.get(channel.id().asShortText());
            if (StringUtil.isNoneBlank(workerid) && workerMap.get(Long.valueOf(workerid)) != null) {
                group.add(channel);
            }
        }
        //群发
        NettyVo result = NettyVo.builder()
                .msg(msg)
                .build();
        group.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(result)));
    }

    //给单个工人发订单信息
    public static void handleOrderWorkerId(String workerid, String msg) {
        Map<String, String> channelMap = bladeRedis.hGetAll("dmj:netty");
        for (Channel channel : clients) {
            if (workerid.equals(channelMap.get(channel.id().asShortText()))) {
                NettyVo result = NettyVo.builder()
                        .msg(msg)
                        .build();
                channel.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(result)));
            }
        }
    }

    //给单个商家发订单信息(和工人的一样)
    public static void handleOrderCuserd(String cuserid, String msg) {
        handleOrderWorkerId(cuserid, msg);
    }
}
